<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>用 AI 生成视频</title>
  <link rel="stylesheet" href="./lib/elementui.css" />
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    html,
    body {
      height: 100%;
      width: 100%;
      font-family: 'Gill Sans', 'Gill Sans MT', Calibri, 'Trebuchet MS', sans-serif;
      overflow: hidden;
    }

    .title {
      text-align: center;
      margin: 40px 0;
    }

    .steps-tag {
      width: 1200px;
      margin-left: 50%;
      transform: translateX(-50%);
    }

    .step-box {
      width: 1050px;
      height: 600px;
      padding: 20px;
      border-radius: 10px;
      background-color: #eee;
      margin-left: 50%;
      transform: translateX(-50%);
      margin-top: 40px;
      margin-bottom: 40px;
    }

    /* 数字人形象选择 */
    .avatars-title {
      color: #666;
      text-indent: 10px;
      margin: 40px 0 10px;
    }

    .avatars-box {
      display: flex;
      justify-content: flex-start;
      flex-wrap: wrap;
    }

    .avatar {
      width: 50px;
      height: 50px;
      border-radius: 5px;
      margin: 10px;
      cursor: pointer;
      background-color: #1ea41e;
      position: relative;
    }

    .avatar:hover {
      background-color: #0e790e;
    }

    .avatar.actived:after {
      content: 'OK';
      position: absolute;
      right: 0;
      bottom: 0;
      width: 25px;
      height: 25px;
      line-height: 25px;
      text-align: center;
      background-color: #333;
      color: #fff;
      font-size: 16px;
      border-top-left-radius: 5px;
    }

    .avatar-one {
      height: 160px;
      max-width: 160px;
      border-radius: 5px;
      margin: 10px;
      cursor: pointer;
      background-color: #e97e7e;
    }

    .avatar-one:hover {
      background-color: #b85656;
    }

    .avatar-one.actived:after {
      content: 'OK';
      position: absolute;
      right: 0;
      bottom: 0;
      width: 25px;
      height: 25px;
      line-height: 25px;
      text-align: center;
      background-color: #333;
      color: #fff;
      font-size: 16px;
      border-top-left-radius: 5px;
    }

    .paly-avatar-btn {
      margin: 40px 0 0 10px;
    }

    .steps {
      display: flex;
      justify-content: center;
    }

    .video-box {
      width: 100vw;
      height: 100vh;
      background-color: rgba(0, 0, 0, 0.9);
      position: fixed;
      top: 0;
      left: 0;
    }

    .show-video {
      width: 1000px;
      height: 600px;
      padding: 10px 10px 10px;
      position: fixed;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      background-color: #000;
      border-radius: 10px;
    }

    .close-video {
      position: fixed;
      color: #fff;
      padding: 20px;
      top: 20px;
      right: 20px;
      font-size: 32px;
      cursor: pointer;
    }

    /* 背景图片选择 */
    .bg-title {
      margin: 20px;
    }

    .bg-tabs {
      margin: 20px;
    }

    .chose-box {
      display: flex;
      align-items: center;
      justify-content: flex-start;
    }

    .chose-box span {
      width: 150px;
    }

    .one-info {
      display: flex;
      align-items: center;
      border-bottom: 1px solid #ccc;
      padding: 10px;
      height: 50px;
    }

    .one-info .title {
      margin-right: 20px;
    }
  </style>
</head>

<body>
  <div id="app">
    <h2 class="title">数字人 AI 视频生成</h2>
    <el-steps :active="stepIndex" align-center class="steps-tag">
      <el-step title="选择数字人物形象" icon="el-icon-s-custom"></el-step>
      <el-step title="输入编辑背景图片" icon="el-icon-picture"></el-step>
      <el-step title="输入视频使用文案" icon="el-icon-edit"></el-step>
      <el-step title="控制参数输出视频" icon="el-icon-video-camera-solid"></el-step>
    </el-steps>

    <!-- 步骤 1 选择数字人形象 -->
    <div class="step-box chose-avatar" v-if="stepIndex === 1">
      <h3 class="avatars-title">请点击选择一个人物形象</h3>
      <div class="avatars-box">
        <el-image class="avatar" v-for="(item, index) in avatars" :class="avatarsIndex === index ? 'actived' : ''"
          :src="item.avatar_states[0].normal_thumbnail_small" shape="square" @click="choseAvatars(item,index)"
          fit="cover"></el-image>
      </div>
      <h3 class="avatars-title">请点击选择人物穿衣风格</h3>
      <div class="avatars-box">
        <el-image class="avatar-one" v-for="(item, index) in oneAvatar"
          :class="oneAvatarIndex === index ? 'actived' : ''" :src="item.normal_thumbnail_small" shape="square"
          :size="50" @click="choseOneAvatar(item, index)" fit="cover"></el-image>
      </div>
      <el-button class="paly-avatar-btn" type="primary" plain icon="el-icon-video-play"
        @click="playAvatarVideo">播放体验视频</el-button>
    </div>

    <!-- 第二步 选择背景图片 or 背景颜色 -->
    <div class="step-box" v-if="stepIndex === 2">
      <h3 class="bg-title">请选择背景模式</h3>
      <el-tabs v-model="bgActive" class="bg-tabs">
        <el-tab-pane label="纯色背景" name="color">
          <div class="chose-box">
            <span>选择背景颜色</span>
            <el-color-picker v-model="choseColor"></el-color-picker>
          </div>

        </el-tab-pane>
        <el-tab-pane label="图片背景" name="image">
          <div class="chose-box">
            <span>背景图片地址</span>
            <el-input v-model="choseImg" placeholder="请输入在线图片地址 JPG、PNG 格式"></el-input>
          </div>
        </el-tab-pane>

        <el-tab-pane label="视频背景" name="video">
          <div class="chose-box">
            <span>背景视频地址</span>
            <el-input v-model="choseMP4" placeholder="请输入在线视频地址 MP4 格式"></el-input>
          </div>
        </el-tab-pane>

      </el-tabs>



    </div>

    <!-- 第三步 输入当前视频需要的文案内容 -->
    <div class="step-box" v-if="stepIndex === 3">
      <el-input type="textarea" placeholder="请输入视频需要的文案" rows="27" v-model="myContent" maxlength="1000" show-word-limit>
      </el-input>
    </div>

    <!-- 配置对应的版本操作 -->
    <div class="step-box" v-if="stepIndex === 4">
      <div class="one-info">
        <span class="title">视频比例</span>
        <el-switch v-model="ratio" active-color="#13ce66" inactive-color="#ff4949" active-value="16:9"
          inactive-value="9:16" active-text="16:9" inactive-text="9:16">
        </el-switch>
      </div>

      <div class="one-info">
        <span class="title">版本控制</span>
        <el-input v-model="version" placeholder="请输入内容" size="small" disabled style="width: 150px;"></el-input>
      </div>

      <div class="one-info">
        <span class="title">字幕模式</span>
        <el-switch v-model="caption_open" active-color="#13ce66" inactive-color="#ff4949" active-text="开启字幕"
          inactive-text="关闭字幕">
        </el-switch>
      </div>

      <div class="one-info">
        <span class="title">头像显示</span>
        <el-switch v-model="avatar_style" active-color="#13ce66" inactive-color="#ff4949" active-value="circle"
          inactive-value="normal" active-text="圆形头像" inactive-text="方形头像">
        </el-switch>
      </div>

      <div class="one-info">
        <span class="title">数字人缩放</span>
        <el-slider v-model="scale" :min="0" :max="1" :step="0.1" :show-stops="true" style="width: 400px;">
        </el-slider>
      </div>

      <div class="one-info">
        <span class="title">数字人声音</span>
        <el-select v-model="voice_id" placeholder="请选择">
          <el-option v-for="item in volicelist" :key="item.value" :label="item.label" :value="item.value">
          </el-option>
        </el-select>
      </div>

      <div class="one-info">
        <span class="title">测试模式</span>
        <el-switch v-model="test" active-color="#13ce66" inactive-color="#ff4949" active-text="测试模式"
          inactive-text="正式模式">
        </el-switch>
      </div>

    </div>


    <div class="steps">
      <el-button-group>
        <el-button type="primary" icon="el-icon-arrow-left" v-if="stepIndex > 1" @click="stepIndex--">上一步</el-button>
        <el-button type="primary" icon="el-icon-arrow-right" v-if="stepIndex < 4" @click="stepIndex++">下一步</el-button>
        <el-button type="primary" icon="el-icon-arrow-right" v-if="stepIndex === 4"
          @click="generateVideo">创建视频</el-button>
      </el-button-group>
    </div>

    <!-- 视频播放界面 -->
    <div class="video-box" v-if="videoShow" @click.self="closeVideo">
      <i class="el-icon-close close-video" @click="closeVideo"></i>
      <video :src="videoSrc" class="show-video" controls autoplay></video>
    </div>
  </div>
</body>
<!-- 导包，导入相关框架依赖及基础数据结构 -->
<script src="./lib/vue.js"></script>
<script src="./lib/elementui.js"></script>
<script src="./lib/axios.js"></script>

<script>

  // 基础 URL 配置，请求拦截及响应拦截
  axios.defaults.baseURL = "https://api.heygen.com/v1/"
  axios.interceptors.request.use(function (config) {
    config.headers = {
      'accept': 'application/json',
      'x-api-key': 'YTk4YmRlNGVhMDNhNDk1OWJiMzZmMmU2YjQ5MDg4ZTAtMTY4NzQ5MDkwOA=='
    };
    return config;
  }, function (err) {
    console.log('网络请求错误', '网络错误');
  });
  axios.interceptors.response.use(function (res) {
    return res.data;
  }, function (err) {
    console.log('网络反馈错误', '网络错误');
  });


  new Vue({
    el: "#app",
    data() {
      return {
        // 步骤选择
        stepIndex: 1,
        // 可选数字人列表
        avatars: [],
        avatarsIndex: 0,
        // 当前选中的数字人换装列表
        oneAvatar: [],
        oneAvatarIndex: 0,

        avatar_id: 'Wilson-insuit-20220722',

        // 视频地址
        videoSrc: '',
        // 视频是否显示
        videoShow: false,

        // 背景选择器
        bgActive: 'image',
        // 颜色选择器
        choseColor: "#007cba",
        choseImg: 'http://qnimgstore.ywfun.cn/64a0034e4017e.jpg',
        choseMP4: 'https://s1.royole.com/ufs/templates/royole/assets/images/flexpai2/pc/ID.mp4',

        // 文案输入
        myContent: '今天是一个好日子，我们一起快乐的做游戏吧！',

        // 参数空子
        ratio: '16:9',
        test: true,
        version: 'v1alpha',
        caption_open: true,
        avatar_style: 'circle',
        scale: 0.5,
        // 默认可爱小孩的声音
        voice_id: "787d136ca6b44868955e01bd3d3047aa",
        volicelist: []
      }
    },
    async mounted() {
      this.getAvatars();
      const res = await axios.get('voice.list')
      console.log(res.data.list);
      const clist = res.data.list.filter(item => item.language === "Chinese")
      this.volicelist = clist.map(item => {
        return {
          label: item.display_name,
          value: item.voice_id
        }
      })
      console.log(this.volicelist);
    },
    methods: {
      // 获取系统预设的数字人信息
      async getAvatars() {
        if (!!localStorage.getItem("avatars")) {
          console.log(JSON.parse(localStorage.getItem("avatars")));
          this.avatars = JSON.parse(localStorage.getItem("avatars"));
          this.oneAvatar = this.avatars[0].avatar_states;
          return;
        }
        const res = await axios.get('avatar.list');
        localStorage.setItem("avatars", JSON.stringify(res.data.avatars))
        console.log(res.data.avatars);
        this.avatars = res.data.avatars;
        this.oneAvatar = this.avatars[0].avatar_states;
      },
      // 选择一个数字人
      choseAvatars(item, index) {
        this.avatarsIndex = index;
        this.oneAvatarIndex = 0;
        this.oneAvatar = item.avatar_states;
      },
      choseOneAvatar(item, index) {
        console.log(item);
        this.oneAvatarIndex = index;
        this.avatar_id = item.id;
      },
      // 播放视频
      playAvatarVideo() {
        this.videoShow = true;
        this.videoSrc = this.avatars[this.avatarsIndex].avatar_states[this.oneAvatarIndex].video_url.grey;
      },
      closeVideo() {
        this.videoShow = false;
        this.videoSrc = '';
      },
      // 创建一个视频
      async generateVideo() {
        let background = "#007cba";
        if (this.bgActive === "color") {
          background = this.choseColor;
        }
        if (this.bgActive === "image") {
          background = this.choseImg;
        }
        if (this.bgActive === "video") {
          background = this.choseMP4;
        }

        const options = {
          background: background,
          "clips": [
            {
              "avatar_id": this.avatar_id,
              "avatar_style": this.avatar_style,
              "input_text": this.myContent,
              "offset": {
                "x": 0.5 - this.scale / 2 - 0.05,
                "y": -0.5 + this.scale / 2 + 0.05
              },
              "scale": this.scale,
              // 注意：声音和国家必须匹配
              "voice_id": this.voice_id
            }
          ],
          "ratio": this.ratio,
          "test": true,
          "version": this.version,
          caption_open: this.caption_open
        }
        console.log(options);
        const res = await axios.post('video.generate', options);
        const loading = this.$loading({
          lock: true,
          text: '视频正在生成中，时间比较长，去喝杯茶吧...',
          spinner: 'el-icon-loading',
          background: 'rgba(0, 0, 0, 0.7)'
        });
        const timer = setInterval(async () => {
          let vres = await axios.get("video_status.get?video_id=" + res.data.video_id);
          console.log(vres);
          if (vres.data.video_url) {
            clearInterval(timer);
            loading.close();
            this.videoShow = true;
            this.videoSrc = vres.data.video_url;
          }
        }, 60000)
      }
    }

  });
</script>

</html>